package org.example.myframework.frame.demo.ws;

import org.example.myframework.frame.demo.config.ws.GetHttpSessioinConfigurator;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpSession;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * ChatEndpoint 当前的类是多例的，会有多个。为此在onlineuser上使用了static，因为期望所有的实例都共享这个map
 */
// 指定前端的访问路径
@ServerEndpoint(value = "/chat", configurator = GetHttpSessioinConfigurator.class)
@Component
public class ChatEndpoint {

    // 线程安全的map：ConcurrentHashMap
    private static final Map<String, Session> onlineUsers = new ConcurrentHashMap<>();

    private HttpSession httpSession;

    /**
     * 连接websocket后被调用
     * @param session 是websocket下的session
     */
    @OnOpen // 连接建立好之后这个方法就会被调用
    public void onOpen(Session session, EndpointConfig config) {
        // 多处有用到
        this.httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
        String user = (String) httpSession.getAttribute("user");
        // 1.将session进行保存，因为连接是多例的
        onlineUsers.put(user, session);
        // 2，广播消息，将登陆的所有的用户推送给所有的用户
        broadcastAllUsers("【系统消息】：" + user + "已上线");
    }

    /**
     * 广播消息
     * 需要给所有的用户推送，所以需要遍历当前map集合
     * @param message
     */
    private void broadcastAllUsers(String message) {
        onlineUsers.forEach((user, session) -> {
            try {
                // 发送同步消息
                session.getBasicRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

    /**
     * 浏览器发送消息到服务端，将会被调用
     * 在当前环境下， 是张三 --> 李四，张三给李四发消息是会调用
     * @param message
     */
    @OnMessage // 接收到浏览器发送过来的数据时，就会被触发
    public void onMessage(String message) {

    }

    /**
     * 断开websocket时会被调用
     * @param session
     */
    @OnClose
    public void onClose(Session session) {
        // 1，从map中移除
        onlineUsers.remove(httpSession.getAttribute("user"));
        // 2，广播消息，当前用户已下线
        broadcastAllUsers("【系统消息】：" + httpSession.getAttribute("user") + "已下线");
    }

}
